package cn.nr19.jian.factory

import cn.nr19.jian.exception.TokenException
import cn.nr19.jian.token.J2Node
import cn.nr19.jian.token.EToken
import cn.nr19.jian.token.Token

/**
 * 代码太多
 * 分多个类，有些乱。 本类就一些固定操作集成。
 *
 */
open class NodeFactory2 {

    var pos = 0 // pos 阅读位置

    // 节点
    // var notes = ArrayList<Node>()

    // token 将 token 解析成 node
    var tokens = ArrayList<Token>()

    // 只需要取一个节点的，就用这个当下一 node ，如键值，键名
    val nullJ2 = J2Node()


    /**
     * 取下一个token,若取到则返回并位置进1 取不到则跳出语法错误
     */
    protected fun nextToken(igNullLine: Boolean, type : EToken, errorTips : String = "语法错误") : Token{
        readNextToken(igNullLine).let {
            if (it != null){
                if (it.type == type) {
                    pos++
                    return it
                }else{
                    throw TokenException.inputError("应输入 ${type} 而不是 ${it.type}(${it.text})",it)
                }
            }
            else{
                if (pos != 0) tokens.get(pos-1).let {
                    throw TokenException.inputError(errorTips,it)
                }else{
                    throw TokenException.inputError("奇怪的错误",if (tokens.size > 0) tokens[tokens.size - 1].pos else 0)
                }
            }

        }

    }

    /**
     * 取下一个token 若取到则返回并位置进1 取不到则跳出语法错误
     */
    protected fun nextToken(igNullLine: Boolean = true) : Token{
        readNextToken(igNullLine).let {
            if (it == null) throw NullException()
            else{
                pos++
                return it
            }
        }
    }

    /**
     * 只读不取(读到位置也不进1,但读到换行也会进1)，不管是否取到位置不会自增，@param igNullLine  true 无视空行，跳过空行， false 若空行则返回
     */
    protected fun readNextToken(igNullLine: Boolean = true) : Token?{
        try {
            if (igNullLine){
                this.tokens.get(pos).let {
                    if (it.type == EToken.PN) {
                        pos++
                        return readNextToken(true)
                    }else{
                        return it
                    }
                }
            }else{
                return this.tokens.get(pos)
            }
        }catch (e : Exception){
            return null
        }
    }

    /**
     * 读下一个值且为空就报错。 只读不取
     */
    protected fun readNextToken3(igNullLine: Boolean = true) : Token{
        try {
            if (igNullLine){
                this.tokens.get(pos).let {
                    if (it.type == EToken.PN) {
                        pos++
                        return readNextToken3(true)
                    }else{
                        return it
                    }
                }
            }else{
                return this.tokens.get(pos)
            }
        }catch (e : Exception){
            throw NullException("代码不完整")
        }

    }



    // *************************************************
    // *********** 基础对象 *****************************
    // obj[suan] ，obj.obj，var++, gfun , arr , num , str , boolean , var , ZKH suan YKH





    /**
     * 取 EONJ， 取不到语法错误
     * KEY : zhi
     */


    protected fun NullException(msg : String="代码不完整") : TokenException {
        return if (pos == 0) TokenException.inputError(msg,0)
        else {
            var token :Token ?= null
            if (tokens.size == 0 ) token = Token()
            else if (pos > tokens.size - 1) token = tokens[tokens.size - 1]
            else token = tokens[pos]
            TokenException.inputError(msg,token)
        }
    }



}